Repository navigation
Report a write tool's outcome as unknown when GitHub's answer is lost or is a 5xx #17
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| - A write tool that got no answer from GitHub, or a 5xx, no longer says it | ||
| failed: it says whether the write took effect is unknown, and to look on | ||
| GitHub before trying again, since a retry may do it twice. The comment | ||
| tools, which answered such a failure with a JSON-RPC error, now answer with | ||
| an error result saying so, and add that rollback has no record of the write | ||
| if it took effect. A read, and a write GitHub refused with a 4xx, still say | ||
| they failed. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -35,7 +35,7 @@ import { | |
| type StateRollbackResult, | ||
| } from '@animalabs/mcpl-core'; | ||
| import { McplRpcError } from './errors.js'; | ||
| import { THREAD_PROPERTY, parseThread, type Parsed } from './tool-support.js'; | ||
| import { THREAD_PROPERTY, field, parseThread, uncertainWrite, type Parsed } from './tool-support.js'; | ||
| import type { GithubStateStore, ThreadLocator } from './state.js'; | ||
| import { | ||
| COMMENTS_FEATURE_SET, | ||
|
|
@@ -357,24 +357,36 @@ export const COMMENT_TOOLS: ToolDefinition[] = [ | |
| export const commentsToolModule: ToolModule = { | ||
| featureSet: COMMENTS_FEATURE_SET, | ||
| tools: COMMENT_TOOLS, | ||
| call(name, args, ctx) { | ||
| switch (name) { | ||
| case TOOL_COMMENT: | ||
| return comment(args, ctx); | ||
| case TOOL_REPLY_IN_THREAD: | ||
| return replyInThread(args, ctx); | ||
| case TOOL_EDIT_OWN_COMMENT: | ||
| return editOwnComment(args, ctx); | ||
| case TOOL_DELETE_OWN_COMMENT: | ||
| return deleteOwnComment(args, ctx); | ||
| case TOOL_UPSERT_STICKY_COMMENT: | ||
| return upsertStickyComment(args, ctx); | ||
| default: | ||
| return Promise.resolve(refuse(`unknown tool: ${name}`)); | ||
| async call(name, args, ctx) { | ||
| try { | ||
| return await callComment(name, args, ctx); | ||
| } catch (err) { | ||
| const uncertain = uncertainWrite(err); | ||
| if (!uncertain) throw err; | ||
| const text = `${field(name)}: ${uncertain} If it did, rollback has no record of it.`; | ||
| ctx.logger.warn('tool call failed', { tool: field(name), detail: text }); | ||
| return refuse(text); | ||
| } | ||
|
Comment on lines
+360
to
369
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Medium severity. Uncertain comment writes are no longer logged anywhere. Before this change, a GitHub error thrown by a comment tool reached the dispatcher in src/server.ts (lines 886-892), which logs |
||
| }, | ||
| }; | ||
|
|
||
| function callComment(name: string, args: Record<string, unknown>, ctx: ToolContext): Promise<ToolResult> { | ||
| switch (name) { | ||
| case TOOL_COMMENT: | ||
| return comment(args, ctx); | ||
| case TOOL_REPLY_IN_THREAD: | ||
| return replyInThread(args, ctx); | ||
| case TOOL_EDIT_OWN_COMMENT: | ||
| return editOwnComment(args, ctx); | ||
| case TOOL_DELETE_OWN_COMMENT: | ||
| return deleteOwnComment(args, ctx); | ||
| case TOOL_UPSERT_STICKY_COMMENT: | ||
| return upsertStickyComment(args, ctx); | ||
| default: | ||
| return Promise.resolve(refuse(`unknown tool: ${name}`)); | ||
| } | ||
| } | ||
|
|
||
| async function comment(args: Record<string, unknown>, ctx: ToolContext): Promise<ToolResult> { | ||
| const thread = parseThreadArg(args.thread, ctx); | ||
| if (!thread.ok) return refuse(thread.error); | ||
|
|
||
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.
Medium severity, test coverage. GraphQL read/write classification is tested only on two simple documents.
isReadRequestparses the body, handles a string or object body, skips leading whitespace and#comments, and treats{as a shorthand query. The only test (resolveReviewThreadagainstlistReviewThreads) uses documents that start withmutationandquerywith no leading whitespace or comments. Nothing tests a leading comment, the anonymous{form, a body that can't be parsed, or a non-/graphqlPOST. Since a wrong classification silently tells the agent a read 'may have taken effect', or tells it a mutation simply 'failed', the regex needs unit tests.