-
Notifications
You must be signed in to change notification settings - Fork 85
implemented a local Player (as spotify is kind of blocked) #1888
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
bmerkle
commented
Feb 3, 2026
- implemented a local Player
- there are currently problems with spotify to get a developer API key and application, hence here is a local Player basic implementation as alternative
…n (based on V2 behaviour) - enhanced calendar client login with better authentication and error handling - fixed some arguments (e.g. passing of dates/search strings(
- there are currently problems with spotify to get a developer API key and application, hence here is a local Player basic implementation as alternative
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This pull request implements a local music player agent as an alternative to Spotify, which the PR description indicates has become difficult to access for developer API keys. The implementation provides basic music playback functionality using platform-native audio players (PowerShell/Windows Media Player on Windows, afplay on macOS, mpv on Linux).
Changes:
- Added new
playerLocalagent package with playback controls, queue management, and file browsing capabilities - Integrated the new agent into the defaultAgentProvider configuration
- Unrelated: Substantially rewrote the calendar agent to integrate with Microsoft Graph API (not mentioned in PR description)
Reviewed changes
Copilot reviewed 15 out of 16 changed files in this pull request and generated 19 comments.
Show a summary per file
| File | Description |
|---|---|
| ts/pnpm-lock.yaml | Added dependencies for the new playerLocal package including play-sound, chalk, debug, and dotenv |
| ts/packages/defaultAgentProvider/package.json | Added music-local workspace dependency |
| ts/packages/defaultAgentProvider/data/config.json | Registered localPlayer agent with name "music-local" |
| ts/packages/agents/playerLocal/package.json | Package definition for the new local player agent |
| ts/packages/agents/playerLocal/src/tsconfig.json | TypeScript configuration for the playerLocal package |
| ts/packages/agents/playerLocal/src/localPlayerService.ts | Core service implementing local audio file playback using platform-specific commands |
| ts/packages/agents/playerLocal/src/agent/localPlayerSchema.ts | TypeScript type definitions for player actions |
| ts/packages/agents/playerLocal/src/agent/localPlayerSchema.json | Schema metadata configuration |
| ts/packages/agents/playerLocal/src/agent/localPlayerSchema.agr | Grammar rules for natural language command parsing (limited coverage) |
| ts/packages/agents/playerLocal/src/agent/localPlayerManifest.json | Agent manifest with emoji and description |
| ts/packages/agents/playerLocal/src/agent/localPlayerHandlers.ts | Action handlers for executing player commands |
| ts/packages/agents/playerLocal/src/agent/localPlayerCommands.ts | Command-line interface handlers for the agent |
| ts/packages/agents/playerLocal/README.md | Documentation for setup and usage |
| ts/packages/agents/calendar/src/calendarActionHandlerV3.ts | Complete rewrite from stub to Graph API integration (unrelated to PR) |
| ts/packages/agents/agentUtils/graphUtils/src/graphClient.ts | Authentication handling improvements for Graph API (unrelated to PR) |
| ts/packages/agents/agentUtils/graphUtils/src/calendarClient.ts | Silent login support for calendar client (unrelated to PR) |
Files not reviewed (1)
- ts/pnpm-lock.yaml: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
The calendar PR is in which is now causing some conflicts. Can you please resolve them and then I will review this PR. |
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
- layout fixes - build, prettier, test run fine now
…stead of async fs.promises.mkdir without await. This fixes the race condition causing "ENOENT: no such file or directory" errors when tests try to write files immediately after creating directories. grammarIntegration.spec.ts: Added describeIf and hasTestKeys imports from test-lib Wrapped the "Grammar Generation via populateCache" describe block with describeIf(..., () => hasTestKeys(), ...) to skip API-dependent tests when no API keys are configured Increased the timeout from 60 seconds to 180 seconds (3 minutes) for the API call test, as LLM calls can be slow Added test-lib to package.json devDependencies
|
@robgruen I have fixed conflicts and the code so it should work now. I ran everything local (build, prettier, test) and also merged in main so it should be ok now. Please have a look, it should be fine now |
Thanks for doing that, it's appreciated! Will take a look. |
| } | ||
|
|
||
| public getMusicFolder(): string { | ||
| return this.musicFolder; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we store the updated music folder location to a settings file so that the user doesn't have to change it every time?
See the list agent for an example of how to write to local session storage: https://github.com/bmerkle/TypeAgent/blob/localPlayer/ts/packages/agents/list/src/listActionHandler.ts
| return { ...this.state }; | ||
| } | ||
|
|
||
| public listFiles(folderPath?: string): Track[] { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| @ <SetVolume> = set volume (to)? $(n:number) (percent)? | ||
| -> { actionName: "setVolume", parameters: { level: $(n) } } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| }; | ||
| } | ||
|
|
||
| // Mute audio |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mute and UnMute could just be one action:
export interface MuteAction {
actionName: "mute";
parameters: {
isMuted: boolean; // true for yes, false for no
}
}
If you can collapse actions like this it's better as things scale because the LLM has less to choose from and can make this action decision as part of it's chain of thought process and doesn't consume additional attention heads.
| return await this.playTrack(this.state.queue[prevIndex]); | ||
| } | ||
|
|
||
| public setVolume(level: number): boolean { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should probably output on non-windows machines that this command doesn't work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same for changeVolume
|
|
||
| if (process.platform === "win32") { | ||
| // Use Windows Media Player via PowerShell | ||
| this.playerProcess = spawn( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| @@ -0,0 +1,135 @@ | |||
| # Local Music Player TypeAgent | |||
|
|
|||
| A TypeAgent for playing local audio files without requiring any external service like Spotify. | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would indicate that the actions in here might collide with the "player" agent and that it's recommended to have one or the other, not both and if you do, you should probably in your intent describe the one you want otherwise you may get the other one.


