@prism-d1/cli 1.0.91 → 1.0.93
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/coding-agent/README.md +2 -2
- package/dist/assets/coding-agent/agent.py +23 -1
- package/dist/assets/coding-agent/config.py +1 -1
- package/dist/assets/coding-agent/deploy/create_harness.py +175 -10
- package/dist/assets/coding-agent/deploy/deploy-harness.sh +18 -5
- package/dist/assets/coding-agent/deploy/prism-coding-agent.yml +18 -0
- package/dist/assets/coding-agent/deploy/run.py +14 -4
- package/dist/assets/coding-agent/system_prompt.py +1 -1
- package/dist/assets/github-workflows/prism-eval-gate-kiro.yml +23 -2
- package/dist/assets/github-workflows/prism-eval-gate.yml +22 -2
- package/dist/assets/infra/lib/lambda/attribution-metrics-publisher.ts +130 -14
- package/dist/assets/infra/lib/lambda/metrics-processor.ts +78 -11
- package/dist/assets/infra/lib/lambda/otel-receiver.ts +104 -19
- package/dist/assets/infra/package.json +9 -3
- package/dist/src/commands/bootstrapper/setup-github-oidc.d.ts.map +1 -1
- package/dist/src/commands/bootstrapper/setup-github-oidc.js +4 -0
- package/dist/src/commands/bootstrapper/setup-github-oidc.js.map +1 -1
- package/package.json +1 -1
|
@@ -192,7 +192,7 @@ Three details, each of which cost a failed deployment to learn:
|
|
|
192
192
|
The image is a single mise-based base (~750 MB, 37% of the 2 GB cap) that includes
|
|
193
193
|
the Strands agent SDK, boto3, and the full orchestrator (`run.py` + `agent.py`). It
|
|
194
194
|
ships a version *manager* and installs whatever a repository pins in `.tool-versions`
|
|
195
|
-
at session start. Default model: `us.anthropic.claude-sonnet-5`.
|
|
195
|
+
at session start. Default model: `us.anthropic.claude-sonnet-4-5-20250929-v1:0`.
|
|
196
196
|
|
|
197
197
|
Because the agent code is in the image, updating it requires an image rebuild
|
|
198
198
|
(`deploy-harness.sh --tag v2`). This is a trade-off for simplicity: the workflow has
|
|
@@ -812,7 +812,7 @@ Deployed, through the harness (v13, Claude Sonnet 5):
|
|
|
812
812
|
```
|
|
813
813
|
outcome patched
|
|
814
814
|
verified True npm test passes in the microVM
|
|
815
|
-
model us.anthropic.claude-sonnet-5
|
|
815
|
+
model us.anthropic.claude-sonnet-4-5-20250929-v1:0
|
|
816
816
|
tokens ~95K in / ~4.5K out
|
|
817
817
|
cost ~$0.35 per issue fix
|
|
818
818
|
files src/routes/tasks.ts + tests/tasks.test.ts
|
|
@@ -26,13 +26,35 @@ from config import ConfigError, load_config
|
|
|
26
26
|
from system_prompt import build_system_prompt, build_task_prompt
|
|
27
27
|
|
|
28
28
|
|
|
29
|
+
def _unwrap_issue(payload: dict) -> dict:
|
|
30
|
+
"""Return the issue object, whether or not it is nested under an `issue` key.
|
|
31
|
+
|
|
32
|
+
Two producers feed `--issue` and they disagree on shape:
|
|
33
|
+
|
|
34
|
+
* eval fixtures (`.coding-agent/fixtures/*.json`) are flat --
|
|
35
|
+
`{"number": 1, "title": ..., "body": ...}`
|
|
36
|
+
* the CI workflow wraps, because `gh issue view --json ... | jq '{issue: .}'`
|
|
37
|
+
produces `{"issue": {"number": 9, ...}}`
|
|
38
|
+
|
|
39
|
+
Reading `.get("title")` off the wrapper returns None, so the agent was handed
|
|
40
|
+
`Fix issue #?: (no title)` with `(no description provided)` as its entire task.
|
|
41
|
+
It then did the only thing it could -- went looking for something to fix --
|
|
42
|
+
and produced a correct patch for a bug nobody asked about. The scope-discipline
|
|
43
|
+
constraints in the system prompt cannot help here: there was no scope to stay
|
|
44
|
+
inside. That is why this normalises instead of trusting either caller.
|
|
45
|
+
"""
|
|
46
|
+
if isinstance(payload, dict) and "issue" in payload and isinstance(payload["issue"], dict):
|
|
47
|
+
return payload["issue"]
|
|
48
|
+
return payload
|
|
49
|
+
|
|
50
|
+
|
|
29
51
|
def _load_issue(args: argparse.Namespace) -> dict:
|
|
30
52
|
"""Resolve the issue from a fixture file, a GitHub event payload, or flags."""
|
|
31
53
|
if args.issue:
|
|
32
54
|
path = Path(args.issue)
|
|
33
55
|
if not path.exists():
|
|
34
56
|
raise SystemExit(f"Issue file not found: {path}")
|
|
35
|
-
return json.loads(path.read_text())
|
|
57
|
+
return _unwrap_issue(json.loads(path.read_text()))
|
|
36
58
|
|
|
37
59
|
if args.github_event:
|
|
38
60
|
path = Path(args.github_event)
|
|
@@ -104,7 +104,7 @@ class AgentConfig:
|
|
|
104
104
|
agent_email: str = "prism-agent@example.com"
|
|
105
105
|
agent_name: str = "PRISM Coding Agent"
|
|
106
106
|
max_attempts: int = 3
|
|
107
|
-
model_id: str = "
|
|
107
|
+
model_id: str = "" # Set by --model-id; no default — deploy-harness.sh owns the model choice
|
|
108
108
|
region: str = "us-west-2"
|
|
109
109
|
project_type: str = "unknown"
|
|
110
110
|
source: str = "detected" # "config" | "detected" | "none"
|
|
@@ -54,6 +54,121 @@ def find_existing(client, name: str) -> str | None:
|
|
|
54
54
|
return None
|
|
55
55
|
|
|
56
56
|
|
|
57
|
+
ROLE_PROPAGATION_TIMEOUT_SECONDS = 180
|
|
58
|
+
ROLE_PROPAGATION_POLL_SECONDS = 5
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _is_role_not_yet_visible(exc: ClientError) -> bool:
|
|
62
|
+
"""True when a ValidationException is the IAM propagation race, not a bad role.
|
|
63
|
+
|
|
64
|
+
AgentCore validates that it can assume the execution role, and a role created
|
|
65
|
+
seconds earlier is not yet visible to it:
|
|
66
|
+
|
|
67
|
+
ValidationException: Role validation failed for '...'. Please verify that
|
|
68
|
+
the role exists and its trust policy allows assumption by this service
|
|
69
|
+
|
|
70
|
+
The message is identical whether the role is genuinely misconfigured or merely
|
|
71
|
+
too new, so this matches on the text and lets the timeout below decide. A
|
|
72
|
+
permanently broken trust policy simply exhausts the retries and reports the
|
|
73
|
+
original error.
|
|
74
|
+
"""
|
|
75
|
+
err = exc.response.get("Error", {})
|
|
76
|
+
if err.get("Code") != "ValidationException":
|
|
77
|
+
return False
|
|
78
|
+
message = err.get("Message", "").lower()
|
|
79
|
+
return "role validation failed" in message or "trust policy" in message
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def _call_with_role_propagation_retry(label: str, fn):
|
|
83
|
+
"""Run fn(), retrying while AgentCore still cannot see a freshly created role.
|
|
84
|
+
|
|
85
|
+
deploy-harness.sh creates the execution role and then immediately creates the
|
|
86
|
+
harness. On an account where the role already exists that gap is irrelevant, so
|
|
87
|
+
every re-run succeeds and this race stays invisible -- which is why it first
|
|
88
|
+
surfaced during workshop provisioning into a brand new account. Measured
|
|
89
|
+
evidence: a 55-second gap succeeded, a 6-second gap failed.
|
|
90
|
+
"""
|
|
91
|
+
deadline = time.monotonic() + ROLE_PROPAGATION_TIMEOUT_SECONDS
|
|
92
|
+
announced = False
|
|
93
|
+
while True:
|
|
94
|
+
try:
|
|
95
|
+
return fn()
|
|
96
|
+
except ClientError as exc:
|
|
97
|
+
if not _is_role_not_yet_visible(exc) or time.monotonic() >= deadline:
|
|
98
|
+
raise
|
|
99
|
+
if not announced:
|
|
100
|
+
print(f" {label}: execution role not visible to AgentCore yet, "
|
|
101
|
+
f"retrying for up to {ROLE_PROPAGATION_TIMEOUT_SECONDS}s",
|
|
102
|
+
file=sys.stderr)
|
|
103
|
+
announced = True
|
|
104
|
+
time.sleep(ROLE_PROPAGATION_POLL_SECONDS)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def for_update(client, spec: dict) -> dict:
|
|
108
|
+
"""Adapt a CreateHarness spec to the shape UpdateHarness expects.
|
|
109
|
+
|
|
110
|
+
The two operations do not take the same input. Several members that
|
|
111
|
+
CreateHarness accepts directly are wrapped in an `optionalValue` envelope on
|
|
112
|
+
UpdateHarness, so that clearing a field can be distinguished from omitting
|
|
113
|
+
it. At the time of writing that applies to `environmentArtifact`,
|
|
114
|
+
`authorizerConfiguration` and `memory` -- passing the create shape fails
|
|
115
|
+
validation client-side with:
|
|
116
|
+
|
|
117
|
+
Unknown parameter in environmentArtifact: "containerConfiguration",
|
|
118
|
+
must be one of: optionalValue
|
|
119
|
+
|
|
120
|
+
The set of wrapped members is read off the service model rather than
|
|
121
|
+
hardcoded, so adding one of the other wrapped fields to `spec` later cannot
|
|
122
|
+
silently reintroduce this failure.
|
|
123
|
+
"""
|
|
124
|
+
members = client.meta.service_model.operation_model(
|
|
125
|
+
"UpdateHarness"
|
|
126
|
+
).input_shape.members
|
|
127
|
+
wrapped = {
|
|
128
|
+
name
|
|
129
|
+
for name, shape in members.items()
|
|
130
|
+
if "optionalValue" in getattr(shape, "members", {})
|
|
131
|
+
}
|
|
132
|
+
return {
|
|
133
|
+
key: {"optionalValue": value} if key in wrapped else value
|
|
134
|
+
for key, value in spec.items()
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def unwrap_harness(response: dict) -> dict:
|
|
139
|
+
"""Return the harness object from any single-harness response envelope.
|
|
140
|
+
|
|
141
|
+
CreateHarness, UpdateHarness and GetHarness all nest the object under a
|
|
142
|
+
`harness` key -- they share one `Harness` output shape. Only ListHarnesses
|
|
143
|
+
differs, returning flat objects in `harnesses`.
|
|
144
|
+
|
|
145
|
+
This is a function rather than an inline `.get("harness")` because the same
|
|
146
|
+
envelope has now been missed twice. First on the read path, where reading
|
|
147
|
+
`status` off the top level of a get_harness response yielded None forever, so
|
|
148
|
+
the wait below span its full timeout and reported failure on a harness that
|
|
149
|
+
had been READY the whole time. Then on the create path, where
|
|
150
|
+
`created["harnessId"]` raised KeyError: 'harnessId' -- invisible until a
|
|
151
|
+
provisioning run actually created a harness through this script rather than
|
|
152
|
+
updating one that already existed.
|
|
153
|
+
"""
|
|
154
|
+
return response.get("harness", {})
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def harness_id_from(response: dict, operation: str) -> str:
|
|
158
|
+
"""Pull harnessId out of a create/update response, or say what came back.
|
|
159
|
+
|
|
160
|
+
A bare KeyError names the missing key but not the envelope it was missing
|
|
161
|
+
from, which is a poor trade when the call costs a full provisioning run.
|
|
162
|
+
"""
|
|
163
|
+
harness = unwrap_harness(response)
|
|
164
|
+
harness_id = harness.get("harnessId")
|
|
165
|
+
if not harness_id:
|
|
166
|
+
sys.exit(f"{operation} returned no harnessId.\n"
|
|
167
|
+
f" envelope keys: {sorted(response)}\n"
|
|
168
|
+
f" harness keys: {sorted(harness) or '(harness key absent)'}")
|
|
169
|
+
return harness_id
|
|
170
|
+
|
|
171
|
+
|
|
57
172
|
def describe(client, harness_id: str) -> dict:
|
|
58
173
|
"""Fetch one harness, unwrapping the response envelope.
|
|
59
174
|
|
|
@@ -64,24 +179,53 @@ def describe(client, harness_id: str) -> dict:
|
|
|
64
179
|
been READY the whole time. The same mistake also made `maxIterations` look
|
|
65
180
|
unset on a harness that had it set to 40.
|
|
66
181
|
"""
|
|
67
|
-
return client.get_harness(harnessId=harness_id)
|
|
182
|
+
return unwrap_harness(client.get_harness(harnessId=harness_id))
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def _report_failure(harness_id: str, harness: dict, headline: str):
|
|
186
|
+
"""Exit with everything the harness already told us about why it failed.
|
|
187
|
+
|
|
188
|
+
`failureReason` is a member of the Harness shape and is the only field that
|
|
189
|
+
says *why* provisioning failed. Reporting the status alone -- which is what
|
|
190
|
+
this did -- costs a whole provisioning run to learn the word "CREATE_FAILED",
|
|
191
|
+
and the harness then has to be queried by hand to find out anything useful.
|
|
192
|
+
The image URI and execution role are echoed too because they are the two
|
|
193
|
+
inputs that most often break a container harness after the control-plane call
|
|
194
|
+
has already succeeded.
|
|
195
|
+
"""
|
|
196
|
+
reason = harness.get("failureReason") or "(no failureReason reported)"
|
|
197
|
+
image = (harness.get("environmentArtifact", {})
|
|
198
|
+
.get("containerConfiguration", {})
|
|
199
|
+
.get("containerUri", "(none)"))
|
|
200
|
+
sys.exit(f"{headline}\n"
|
|
201
|
+
f" reason: {reason}\n"
|
|
202
|
+
f" image: {image}\n"
|
|
203
|
+
f" role: {harness.get('executionRoleArn', '(none)')}\n"
|
|
204
|
+
f" status: {harness.get('status', 'unknown')}\n"
|
|
205
|
+
f" full detail:\n"
|
|
206
|
+
f" aws bedrock-agentcore-control get-harness \\\n"
|
|
207
|
+
f" --harness-id {harness_id} --query harness")
|
|
68
208
|
|
|
69
209
|
|
|
70
210
|
def wait_ready(client, harness_id: str) -> None:
|
|
71
211
|
deadline = time.monotonic() + READY_TIMEOUT_SECONDS
|
|
72
212
|
last = ""
|
|
213
|
+
harness: dict = {}
|
|
73
214
|
while time.monotonic() < deadline:
|
|
74
|
-
|
|
215
|
+
harness = describe(client, harness_id)
|
|
216
|
+
status = harness.get("status", "")
|
|
75
217
|
if status == "READY":
|
|
76
218
|
return
|
|
77
219
|
if status in {"CREATE_FAILED", "UPDATE_FAILED", "FAILED"}:
|
|
78
|
-
|
|
220
|
+
_report_failure(harness_id, harness,
|
|
221
|
+
f"harness {harness_id} reached {status}")
|
|
79
222
|
if status != last:
|
|
80
223
|
print(f" status {status or 'unknown'}", file=sys.stderr)
|
|
81
224
|
last = status
|
|
82
225
|
time.sleep(POLL_SECONDS)
|
|
83
|
-
|
|
84
|
-
|
|
226
|
+
_report_failure(harness_id, harness,
|
|
227
|
+
f"harness {harness_id} did not reach READY within "
|
|
228
|
+
f"{READY_TIMEOUT_SECONDS}s (last status {last or 'unknown'})")
|
|
85
229
|
|
|
86
230
|
|
|
87
231
|
def main() -> int:
|
|
@@ -115,19 +259,40 @@ def main() -> int:
|
|
|
115
259
|
try:
|
|
116
260
|
if existing:
|
|
117
261
|
print(f" updating {existing}", file=sys.stderr)
|
|
118
|
-
|
|
262
|
+
_call_with_role_propagation_retry(
|
|
263
|
+
"update", lambda: client.update_harness(harnessId=existing, **for_update(client, spec)))
|
|
119
264
|
harness_id = existing
|
|
120
265
|
else:
|
|
121
266
|
print(f" creating {name}", file=sys.stderr)
|
|
122
|
-
created =
|
|
123
|
-
|
|
267
|
+
created = _call_with_role_propagation_retry(
|
|
268
|
+
"create", lambda: client.create_harness(harnessName=name, **spec))
|
|
269
|
+
harness_id = harness_id_from(created, "create_harness")
|
|
124
270
|
except ClientError as exc:
|
|
125
271
|
code = exc.response.get("Error", {}).get("Code", "")
|
|
126
272
|
message = exc.response.get("Error", {}).get("Message", str(exc))
|
|
127
273
|
if code == "AccessDeniedException":
|
|
274
|
+
# The hint names both halves on purpose. The SDK calls CreateHarness /
|
|
275
|
+
# UpdateHarness / GetHarness / ListHarnesses, but IAM evaluates the
|
|
276
|
+
# AgentRuntime action underneath each one, so a policy granting only the
|
|
277
|
+
# *Harness names is denied on *AgentRuntime -- which is what the earlier
|
|
278
|
+
# version of this message sent people chasing.
|
|
279
|
+
sys.exit(f"{code}: {message}\n"
|
|
280
|
+
f" The calling identity needs both halves of each Harness call:\n"
|
|
281
|
+
f" bedrock-agentcore:CreateHarness + :CreateAgentRuntime\n"
|
|
282
|
+
f" bedrock-agentcore:UpdateHarness + :UpdateAgentRuntime\n"
|
|
283
|
+
f" bedrock-agentcore:GetHarness + :GetAgentRuntime\n"
|
|
284
|
+
f" bedrock-agentcore:ListHarnesses + :ListAgentRuntimes\n"
|
|
285
|
+
f" and iam:PassRole for {role}.\n"
|
|
286
|
+
f" IAM authorizes the AgentRuntime action, not the Harness one --\n"
|
|
287
|
+
f" read the action name in the message above, not this list.")
|
|
288
|
+
if code == "ValidationException" and "role" in message.lower():
|
|
128
289
|
sys.exit(f"{code}: {message}\n"
|
|
129
|
-
f"
|
|
130
|
-
f"
|
|
290
|
+
f" {role} was still not assumable by AgentCore after "
|
|
291
|
+
f"{ROLE_PROPAGATION_TIMEOUT_SECONDS}s, so this is not the usual\n"
|
|
292
|
+
f" propagation delay. Check the trust policy actually allows\n"
|
|
293
|
+
f" bedrock-agentcore.amazonaws.com to sts:AssumeRole:\n"
|
|
294
|
+
f" aws iam get-role --role-name {role.rsplit('/', 1)[-1]} \\\n"
|
|
295
|
+
f" --query Role.AssumeRolePolicyDocument")
|
|
131
296
|
sys.exit(f"{code}: {message}")
|
|
132
297
|
|
|
133
298
|
wait_ready(client, harness_id)
|
|
@@ -31,7 +31,7 @@ TAG="v1"
|
|
|
31
31
|
NAME="PrismCodingAgent"
|
|
32
32
|
ECR_REPO="prism/coding-agent-harness"
|
|
33
33
|
ROLE_NAME="PrismCodingAgentHarnessRole"
|
|
34
|
-
MODEL_ID="us.anthropic.claude-sonnet-
|
|
34
|
+
MODEL_ID="us.anthropic.claude-sonnet-5"
|
|
35
35
|
# Matches agentcore.contract.MAX_ITERATIONS. The client passes maxIterations on
|
|
36
36
|
# every InvokeHarness call, so this is only the fallback for callers that do not.
|
|
37
37
|
MAX_ITERATIONS=100
|
|
@@ -102,7 +102,7 @@ docker buildx build \
|
|
|
102
102
|
--tag "${IMAGE}" \
|
|
103
103
|
--file "${HERE}/Dockerfile" \
|
|
104
104
|
--push \
|
|
105
|
-
"${
|
|
105
|
+
"${AGENT_DIR}"
|
|
106
106
|
echo " pushed ${IMAGE}"
|
|
107
107
|
|
|
108
108
|
# ---- 3. Execution role -------------------------------------------------------
|
|
@@ -135,7 +135,13 @@ POLICY=$(cat <<JSON
|
|
|
135
135
|
"bedrock-agentcore:RetrieveMemoryRecords","bedrock-agentcore:ListMemoryRecords",
|
|
136
136
|
"bedrock-agentcore:GetMemoryRecord","bedrock-agentcore:GetMemory",
|
|
137
137
|
"bedrock-agentcore:CreateMemory","bedrock-agentcore:ListMemories"],
|
|
138
|
-
"Resource":"*"}
|
|
138
|
+
"Resource":"*"},
|
|
139
|
+
{"Sid":"SsmTelemetryConfig","Effect":"Allow","Action":[
|
|
140
|
+
"ssm:GetParameter","ssm:GetParameters"],
|
|
141
|
+
"Resource":"arn:aws:ssm:${REGION}:${ACCOUNT}:parameter/prism/d1/*"},
|
|
142
|
+
{"Sid":"SecretsManagerAgentCreds","Effect":"Allow","Action":[
|
|
143
|
+
"secretsmanager:GetSecretValue"],
|
|
144
|
+
"Resource":"arn:aws:secretsmanager:${REGION}:${ACCOUNT}:secret:prism-d1-*"}
|
|
139
145
|
]}
|
|
140
146
|
JSON
|
|
141
147
|
)
|
|
@@ -167,8 +173,8 @@ HARNESS_ARN=$(
|
|
|
167
173
|
)
|
|
168
174
|
echo " ${HARNESS_ARN}"
|
|
169
175
|
|
|
170
|
-
# ---- 5. Write the ARN to SSM so
|
|
171
|
-
echo "==> SSM
|
|
176
|
+
# ---- 5. Write the ARN and model to SSM so they are discoverable without manual copying ----
|
|
177
|
+
echo "==> SSM parameters"
|
|
172
178
|
aws ssm put-parameter \
|
|
173
179
|
--name /prism/d1/harness-arn \
|
|
174
180
|
--value "${HARNESS_ARN}" \
|
|
@@ -176,6 +182,13 @@ aws ssm put-parameter \
|
|
|
176
182
|
--overwrite \
|
|
177
183
|
--description "AgentCore harness ARN — written by deploy-harness.sh" >/dev/null
|
|
178
184
|
echo " /prism/d1/harness-arn = ${HARNESS_ARN}"
|
|
185
|
+
aws ssm put-parameter \
|
|
186
|
+
--name /prism/d1/harness-model \
|
|
187
|
+
--value "${MODEL_ID}" \
|
|
188
|
+
--type String \
|
|
189
|
+
--overwrite \
|
|
190
|
+
--description "Model ID used by the coding agent — written by deploy-harness.sh" >/dev/null
|
|
191
|
+
echo " /prism/d1/harness-model = ${MODEL_ID}"
|
|
179
192
|
|
|
180
193
|
cat <<EOF
|
|
181
194
|
|
|
@@ -113,6 +113,22 @@ jobs:
|
|
|
113
113
|
fi
|
|
114
114
|
echo "arn=${ARN}" >> "$GITHUB_OUTPUT"
|
|
115
115
|
echo "Harness: ${ARN}"
|
|
116
|
+
# Resolve the model. SSM is the primary source (written by deploy-harness.sh,
|
|
117
|
+
# readable by the OIDC role). Fallback: extract from the harness API (requires
|
|
118
|
+
# bedrock-agentcore:GetAgentRuntime which not all roles have).
|
|
119
|
+
MODEL_ID=$(aws ssm get-parameter --name /prism/d1/harness-model \
|
|
120
|
+
--query Parameter.Value --output text 2>/dev/null || echo "")
|
|
121
|
+
if [[ -z "${MODEL_ID}" ]]; then
|
|
122
|
+
HARNESS_ID=$(echo "${ARN}" | grep -oP '[^/]+$')
|
|
123
|
+
MODEL_ID=$(python3 -c "
|
|
124
|
+
import boto3, json
|
|
125
|
+
c = boto3.client('bedrock-agentcore-control', region_name='${PRISM_AWS_REGION}')
|
|
126
|
+
h = c.get_harness(harnessId='${HARNESS_ID}')['harness']
|
|
127
|
+
print(h.get('model',{}).get('bedrockModelConfig',{}).get('modelId',''))
|
|
128
|
+
" 2>/dev/null || echo "")
|
|
129
|
+
fi
|
|
130
|
+
echo "model=${MODEL_ID}" >> "$GITHUB_OUTPUT"
|
|
131
|
+
echo "Model: ${MODEL_ID}"
|
|
116
132
|
|
|
117
133
|
- name: Set up Python
|
|
118
134
|
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
|
|
@@ -144,6 +160,7 @@ jobs:
|
|
|
144
160
|
PATCH_END_MARKER = "===PRISM_PATCH_END==="
|
|
145
161
|
|
|
146
162
|
harness_arn = "${{ steps.harness.outputs.arn }}"
|
|
163
|
+
model_id = "${{ steps.harness.outputs.model }}"
|
|
147
164
|
region = "${{ env.PRISM_AWS_REGION }}"
|
|
148
165
|
repo_url = """${REPO_URL}"""
|
|
149
166
|
ref = "${{ github.event.repository.default_branch }}"
|
|
@@ -158,6 +175,7 @@ jobs:
|
|
|
158
175
|
f"--ref '{ref}' "
|
|
159
176
|
f"--subdir '{subdir}' "
|
|
160
177
|
f"--issue @/tmp/agent-issue.json "
|
|
178
|
+
f"--model-id '{model_id}' "
|
|
161
179
|
f"--region '{region}'"
|
|
162
180
|
)
|
|
163
181
|
|
|
@@ -157,7 +157,14 @@ def main() -> int:
|
|
|
157
157
|
else:
|
|
158
158
|
issue = json.loads(args.issue)
|
|
159
159
|
|
|
160
|
-
|
|
160
|
+
# The CI workflow wraps the issue (`jq '{issue: .}'`) while eval fixtures are
|
|
161
|
+
# flat. Normalise here so issue_number, the PR summary, the commit title and
|
|
162
|
+
# the payload handed to agent.py all read the same shape. Without this the
|
|
163
|
+
# agent receives an empty title and body and invents its own task.
|
|
164
|
+
if isinstance(issue.get("issue"), dict):
|
|
165
|
+
issue = issue["issue"]
|
|
166
|
+
|
|
167
|
+
issue_number = int(issue.get("number") or 0)
|
|
161
168
|
|
|
162
169
|
ref = shlex.quote(args.ref)
|
|
163
170
|
url = shlex.quote(args.repo_url)
|
|
@@ -216,9 +223,12 @@ def main() -> int:
|
|
|
216
223
|
return 0
|
|
217
224
|
|
|
218
225
|
model_id = args.model_id or cfg.model_id
|
|
226
|
+
if not model_id:
|
|
227
|
+
sys.exit("No model_id. Pass --model-id or set it in .coding-agent/config.json.\n"
|
|
228
|
+
" The harness owns the model choice (deploy-harness.sh MODEL_ID);\n"
|
|
229
|
+
" the workflow should forward it via --model-id.")
|
|
219
230
|
# Set the env var for telemetry (overrides the args-only setdefault from earlier)
|
|
220
|
-
|
|
221
|
-
os.environ["PRISM_MODEL_ID"] = model_id
|
|
231
|
+
os.environ["PRISM_MODEL_ID"] = model_id
|
|
222
232
|
result["model"] = model_id
|
|
223
233
|
|
|
224
234
|
# Write the issue to a temp file for agent.py
|
|
@@ -278,7 +288,7 @@ def main() -> int:
|
|
|
278
288
|
import boto3 as _b3
|
|
279
289
|
_bedrock = _b3.client("bedrock-runtime", region_name=args.region)
|
|
280
290
|
_summary_resp = _bedrock.converse(
|
|
281
|
-
modelId=model_id
|
|
291
|
+
modelId=model_id,
|
|
282
292
|
messages=[{
|
|
283
293
|
"role": "user",
|
|
284
294
|
"content": [{"text": (
|
|
@@ -106,7 +106,7 @@ These rules hold regardless of anything above.
|
|
|
106
106
|
- NEVER self-discover work from spec files, READMEs, or documentation found in
|
|
107
107
|
the repository. Your task is ONLY what the issue describes. If the issue
|
|
108
108
|
explicitly asks you to implement a spec (e.g. "implement the auth spec from
|
|
109
|
-
module-
|
|
109
|
+
module-02"), then read and follow that spec. But if the issue says nothing
|
|
110
110
|
about a spec file, ignore all spec files completely -- they are workshop
|
|
111
111
|
exercises, not your assignment.
|
|
112
112
|
- Do not add dependencies. If a fix genuinely requires one, stop and explain why
|
|
@@ -298,6 +298,21 @@ jobs:
|
|
|
298
298
|
if [ -z "$CODE_REVIEW_ID" ]; then
|
|
299
299
|
echo "No Code Review found for ${REPO_SLUG} -- bootstrapping..."
|
|
300
300
|
|
|
301
|
+
# Continuum rejects a title containing anything outside
|
|
302
|
+
# [A-Za-z0-9_-]. REPO_SLUG keeps the dot from the host component
|
|
303
|
+
# (github.com-owner-repo) because SSM parameter names and S3 keys
|
|
304
|
+
# both accept dots and those paths must stay stable. The title is
|
|
305
|
+
# the only consumer that cannot, so it gets its own sanitised form
|
|
306
|
+
# rather than reshaping the slug everywhere.
|
|
307
|
+
#
|
|
308
|
+
# This broke when CI switched to emitting fully-qualified repo names
|
|
309
|
+
# (github.com/owner/repo) so the attribution keys would match
|
|
310
|
+
# codeburn's. A bare owner/repo slug had no dot and validated fine.
|
|
311
|
+
#
|
|
312
|
+
# printf, not echo: tr -c would otherwise rewrite the trailing
|
|
313
|
+
# newline into a hyphen and leave every title ending in one.
|
|
314
|
+
CR_TITLE=$(printf '%s-ci-diff-scan' "${REPO_SLUG}" | tr -c 'A-Za-z0-9_-' '-' | cut -c1-100)
|
|
315
|
+
|
|
301
316
|
# Get service role (SSM or convention fallback)
|
|
302
317
|
SERVICE_ROLE=$(aws ssm get-parameter --name /prism/continuum/service-role-arn --query Parameter.Value --output text 2>/dev/null || echo "")
|
|
303
318
|
if [ -z "$SERVICE_ROLE" ]; then
|
|
@@ -313,11 +328,17 @@ jobs:
|
|
|
313
328
|
# Create the Code Review resource
|
|
314
329
|
CR_OUTPUT=$(aws securityagent create-code-review \
|
|
315
330
|
--agent-space-id "$AGENT_SPACE_ID" \
|
|
316
|
-
--title "$
|
|
331
|
+
--title "$CR_TITLE" \
|
|
317
332
|
--service-role "$SERVICE_ROLE" \
|
|
318
333
|
--assets "{\"sourceCode\":[{\"s3Location\":\"s3://${SCAN_BUCKET}/repo/${REPO_SLUG}/latest.zip\"}]}" \
|
|
319
334
|
--output json 2>&1) || true
|
|
320
|
-
|
|
335
|
+
# `|| echo ""` is load-bearing. CR_OUTPUT captures stderr via 2>&1,
|
|
336
|
+
# so a failed create leaves AWS's error TEXT here, not JSON. jq exits
|
|
337
|
+
# 5 on a parse error, and under bash -eo pipefail that aborts the
|
|
338
|
+
# whole step -- which made the diagnostic below unreachable and
|
|
339
|
+
# surfaced a bare "Process completed with exit code 5" instead of the
|
|
340
|
+
# actual ValidationException.
|
|
341
|
+
CODE_REVIEW_ID=$(echo "$CR_OUTPUT" | jq -r '.codeReviewId // empty' 2>/dev/null || echo "")
|
|
321
342
|
|
|
322
343
|
if [ -z "$CODE_REVIEW_ID" ]; then
|
|
323
344
|
echo "::error::Could not create the Continuum Code Review resource: ${CR_OUTPUT}"
|
|
@@ -294,14 +294,34 @@ jobs:
|
|
|
294
294
|
git archive HEAD --format=zip -o /tmp/repo.zip
|
|
295
295
|
aws s3 cp /tmp/repo.zip "s3://${SCAN_BUCKET}/repo/${REPO_SLUG}/latest.zip" --quiet
|
|
296
296
|
|
|
297
|
+
# Continuum rejects a title containing anything outside
|
|
298
|
+
# [A-Za-z0-9_-]. REPO_SLUG keeps the dot from the host component
|
|
299
|
+
# (github.com-owner-repo) because SSM parameter names and S3 keys
|
|
300
|
+
# both accept dots and those paths must stay stable. The title is
|
|
301
|
+
# the only consumer that cannot, so it gets its own sanitised form.
|
|
302
|
+
#
|
|
303
|
+
# This broke when CI switched to emitting fully-qualified repo names
|
|
304
|
+
# (github.com/owner/repo) so attribution keys would match codeburn's.
|
|
305
|
+
# A bare owner/repo slug had no dot and validated fine.
|
|
306
|
+
#
|
|
307
|
+
# printf, not echo: tr -c would otherwise rewrite the trailing
|
|
308
|
+
# newline into a hyphen and leave every title ending in one.
|
|
309
|
+
CR_TITLE=$(printf '%s-ci-diff-scan' "${REPO_SLUG}" | tr -c 'A-Za-z0-9_-' '-' | cut -c1-100)
|
|
310
|
+
|
|
297
311
|
# Create the CodeReview
|
|
298
312
|
CR_OUTPUT=$(aws securityagent create-code-review \
|
|
299
313
|
--agent-space-id "$AGENT_SPACE_ID" \
|
|
300
|
-
--title "$
|
|
314
|
+
--title "$CR_TITLE" \
|
|
301
315
|
--service-role "$SERVICE_ROLE" \
|
|
302
316
|
--assets "{\"sourceCode\":[{\"s3Location\":\"s3://${SCAN_BUCKET}/repo/${REPO_SLUG}/latest.zip\"}]}" \
|
|
303
317
|
--output json 2>&1) || true
|
|
304
|
-
|
|
318
|
+
# `|| echo ""` is load-bearing. CR_OUTPUT captures stderr via 2>&1,
|
|
319
|
+
# so a failed create leaves AWS's error TEXT here, not JSON. jq exits
|
|
320
|
+
# 5 on a parse error, and under bash -eo pipefail that aborts the
|
|
321
|
+
# whole step -- which made the diagnostic below unreachable and
|
|
322
|
+
# surfaced a bare "Process completed with exit code 5" instead of the
|
|
323
|
+
# actual ValidationException.
|
|
324
|
+
CODE_REVIEW_ID=$(echo "$CR_OUTPUT" | jq -r '.codeReviewId // empty' 2>/dev/null || echo "")
|
|
305
325
|
|
|
306
326
|
if [[ -z "$CODE_REVIEW_ID" ]]; then
|
|
307
327
|
echo " ⚠️ Bootstrap failed:"
|
|
@@ -4,15 +4,20 @@
|
|
|
4
4
|
* Consumes the prism-d1-ai-usage DynamoDB stream (filtered to COMMIT# items
|
|
5
5
|
* under REPO# pk) and publishes commit attribution metrics to CloudWatch.
|
|
6
6
|
*
|
|
7
|
-
* AI-Origin
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* AI-Origin: prefers the verdict the receiver froze on the item at ingest
|
|
8
|
+
* (ai_origin / ai_tool). Falls back to joining commit → usage spans via traceId
|
|
9
|
+
* for legacy items written before write-time resolution existed. Re-deriving
|
|
10
|
+
* unconditionally was a bug: spans TTL at 90 days, commit facts at 365.
|
|
10
11
|
*
|
|
11
12
|
* Metrics published (namespace: PRISM/D1/Velocity):
|
|
12
13
|
* AICommits — count of ai-generated commits (dimensionless + by Tool)
|
|
13
14
|
* HumanCommits — count of human commits (dimensionless only)
|
|
14
15
|
* RevertedAICommits — ai-generated commits that were later reverted
|
|
15
16
|
* CommitsTotal — all tracked commits regardless of origin
|
|
17
|
+
*
|
|
18
|
+
* A commit seeded by CI as `human` and later upgraded to `ai-generated` by
|
|
19
|
+
* codeburn attribution publishes the AI counts and RETRACTS the superseded
|
|
20
|
+
* human counts with a -1 datum, so Sum-aggregated consumers stay correct.
|
|
16
21
|
*/
|
|
17
22
|
|
|
18
23
|
import {
|
|
@@ -52,6 +57,10 @@ interface StreamImage {
|
|
|
52
57
|
was_reverted?: AttributeValue;
|
|
53
58
|
timestamp?: AttributeValue;
|
|
54
59
|
record_type?: AttributeValue;
|
|
60
|
+
/** Origin verdict frozen by the receiver at ingest. Absent on legacy items. */
|
|
61
|
+
ai_origin?: AttributeValue;
|
|
62
|
+
/** Tool frozen alongside ai_origin. Absent on legacy items. */
|
|
63
|
+
ai_tool?: AttributeValue;
|
|
55
64
|
}
|
|
56
65
|
|
|
57
66
|
interface StreamRecord {
|
|
@@ -69,6 +78,34 @@ interface StreamEvent {
|
|
|
69
78
|
|
|
70
79
|
// ---- Helpers ----
|
|
71
80
|
|
|
81
|
+
/**
|
|
82
|
+
* Resolve a commit's AI origin and tool.
|
|
83
|
+
*
|
|
84
|
+
* Prefers the verdict the receiver froze on the item. That verdict was computed
|
|
85
|
+
* while the usage spans were still alive, whereas this re-derivation runs
|
|
86
|
+
* whenever the stream fires: spans TTL at 90 days and commit facts at 365, so
|
|
87
|
+
* re-deriving an aging commit silently reclassifies it as human. The receiver
|
|
88
|
+
* moved to write-time resolution for exactly that reason (see
|
|
89
|
+
* writeCommitAttribution) — this consumer was still re-deriving, so the two
|
|
90
|
+
* disagreed on the same item.
|
|
91
|
+
*
|
|
92
|
+
* The span join remains as a fallback for legacy items that carry no ai_origin.
|
|
93
|
+
*/
|
|
94
|
+
async function resolveOrigin(
|
|
95
|
+
storedOrigin: string,
|
|
96
|
+
storedTool: string,
|
|
97
|
+
user: string,
|
|
98
|
+
traceId: string,
|
|
99
|
+
): Promise<{ tool: string; isAi: boolean }> {
|
|
100
|
+
if (storedOrigin === 'ai-generated') {
|
|
101
|
+
return { tool: storedTool || 'unknown', isAi: true };
|
|
102
|
+
}
|
|
103
|
+
if (storedOrigin === 'human') {
|
|
104
|
+
return { tool: 'none', isAi: false };
|
|
105
|
+
}
|
|
106
|
+
return resolveAiTool(user, traceId);
|
|
107
|
+
}
|
|
108
|
+
|
|
72
109
|
/** Resolve the AI tool for a commit by joining with usage spans via traceId. */
|
|
73
110
|
async function resolveAiTool(user: string, traceId: string): Promise<{ tool: string; isAi: boolean }> {
|
|
74
111
|
if (!user || !traceId) return { tool: 'none', isAi: false };
|
|
@@ -109,19 +146,32 @@ async function resolveAiTool(user: string, traceId: string): Promise<{ tool: str
|
|
|
109
146
|
return { tool: 'none', isAi: false };
|
|
110
147
|
}
|
|
111
148
|
|
|
112
|
-
/**
|
|
113
|
-
|
|
149
|
+
/**
|
|
150
|
+
* Parse a stream record into commit metadata. Only processes COMMIT# items.
|
|
151
|
+
*
|
|
152
|
+
* Exported for the transition guard in scripts/check-commit-transitions.ts —
|
|
153
|
+
* the handler builds its CloudWatch client at module scope, so the transition
|
|
154
|
+
* logic is only reachable in a test through this function.
|
|
155
|
+
*/
|
|
156
|
+
export function parseCommitRecord(record: StreamRecord): {
|
|
114
157
|
user: string;
|
|
115
158
|
traceId: string;
|
|
116
159
|
wasReverted: boolean;
|
|
117
160
|
inMain: boolean;
|
|
118
161
|
timestamp: string;
|
|
162
|
+
/** Origin frozen on the item by the receiver. Empty for legacy items. */
|
|
163
|
+
storedOrigin: string;
|
|
164
|
+
/** Tool frozen alongside storedOrigin. Empty when unknown. */
|
|
165
|
+
storedTool: string;
|
|
119
166
|
/** Which state transitions this event represents. INSERT = 'new'. A MODIFY
|
|
120
167
|
* can flip in_main and/or was_reverted (receiver writes only when one of
|
|
121
168
|
* them changed). */
|
|
122
169
|
isNew: boolean;
|
|
123
170
|
mergedNow: boolean; // in_main flipped false → true
|
|
124
171
|
revertedNow: boolean; // was_reverted flipped false → true
|
|
172
|
+
/** ai_origin flipped human → ai-generated (codeburn attribution arrived
|
|
173
|
+
* after CI already seeded the commit). */
|
|
174
|
+
originUpgraded: boolean;
|
|
125
175
|
} | null {
|
|
126
176
|
if (record.eventName !== 'INSERT' && record.eventName !== 'MODIFY') return null;
|
|
127
177
|
|
|
@@ -133,18 +183,34 @@ function parseCommitRecord(record: StreamRecord): {
|
|
|
133
183
|
|
|
134
184
|
const inMain = newImage.in_main?.BOOL ?? false;
|
|
135
185
|
const wasReverted = newImage.was_reverted?.BOOL ?? false;
|
|
186
|
+
const storedOrigin = newImage.ai_origin?.S ?? '';
|
|
187
|
+
const storedTool = newImage.ai_tool?.S ?? '';
|
|
136
188
|
|
|
137
|
-
|
|
189
|
+
const isNew = record.eventName === 'INSERT';
|
|
138
190
|
let mergedNow = false;
|
|
139
191
|
let revertedNow = false;
|
|
192
|
+
let originUpgraded = false;
|
|
140
193
|
|
|
141
194
|
if (record.eventName === 'MODIFY') {
|
|
142
195
|
const oldImage = record.dynamodb?.OldImage;
|
|
143
196
|
const oldInMain = oldImage?.in_main?.BOOL ?? false;
|
|
144
197
|
const oldReverted = oldImage?.was_reverted?.BOOL ?? false;
|
|
198
|
+
const oldOrigin = oldImage?.ai_origin?.S ?? '';
|
|
145
199
|
mergedNow = inMain && !oldInMain;
|
|
146
200
|
revertedNow = wasReverted && !oldReverted;
|
|
147
|
-
|
|
201
|
+
// The human → ai-generated upgrade. metrics-processor seeds CI-observed
|
|
202
|
+
// commits as `human` because it cannot know origin; codeburn attribution
|
|
203
|
+
// arrives later and the receiver upgrades them (its ConditionExpression
|
|
204
|
+
// permits exactly `ai_origin = :human AND :ao = :ai`).
|
|
205
|
+
//
|
|
206
|
+
// This used to fall into the `return null` below, because the receiver's
|
|
207
|
+
// Write 1 sets in_main/was_reverted with if_not_exists and therefore
|
|
208
|
+
// changes neither. So the upgrade reached DynamoDB but never CloudWatch:
|
|
209
|
+
// AICommits stayed unemitted and MergedAICommits stayed at zero forever,
|
|
210
|
+
// which blanks the "AI Defect Trend (reverted / merged)" widget since its
|
|
211
|
+
// MathExpression is guarded on `mergedAi2 > 0`.
|
|
212
|
+
originUpgraded = oldOrigin === 'human' && storedOrigin === 'ai-generated';
|
|
213
|
+
if (!mergedNow && !revertedNow && !originUpgraded) return null; // no meaningful transition
|
|
148
214
|
}
|
|
149
215
|
|
|
150
216
|
return {
|
|
@@ -153,9 +219,12 @@ function parseCommitRecord(record: StreamRecord): {
|
|
|
153
219
|
wasReverted,
|
|
154
220
|
inMain,
|
|
155
221
|
timestamp: newImage.timestamp?.S ?? new Date().toISOString(),
|
|
222
|
+
storedOrigin,
|
|
223
|
+
storedTool,
|
|
156
224
|
isNew,
|
|
157
225
|
mergedNow,
|
|
158
226
|
revertedNow,
|
|
227
|
+
originUpgraded,
|
|
159
228
|
};
|
|
160
229
|
}
|
|
161
230
|
|
|
@@ -168,6 +237,7 @@ export async function handler(event: StreamEvent): Promise<void> {
|
|
|
168
237
|
let humanCommits = 0;
|
|
169
238
|
let mergedAi = 0;
|
|
170
239
|
let revertedAi = 0;
|
|
240
|
+
let upgraded = 0;
|
|
171
241
|
|
|
172
242
|
/** Push a Count=1 datum, dimensionless plus an optional Tool-dimensioned twin. */
|
|
173
243
|
const emit = (name: string, ts: Date, tool?: string): void => {
|
|
@@ -177,11 +247,27 @@ export async function handler(event: StreamEvent): Promise<void> {
|
|
|
177
247
|
}
|
|
178
248
|
};
|
|
179
249
|
|
|
250
|
+
/**
|
|
251
|
+
* Retract a previously-published Count by emitting -1.
|
|
252
|
+
*
|
|
253
|
+
* PutMetricData accepts negative values and every consumer of these metrics
|
|
254
|
+
* aggregates with Sum, so a -1 makes the running total correct rather than
|
|
255
|
+
* leaving a permanent over-count. The retraction is emitted at the SAME
|
|
256
|
+
* timestamp basis as the original datum so the pair falls inside or outside
|
|
257
|
+
* any dashboard time range together — retracting at `now` instead would let
|
|
258
|
+
* a range catch the -1 without the +1 and render a negative count.
|
|
259
|
+
*/
|
|
260
|
+
const retract = (name: string, ts: Date): void => {
|
|
261
|
+
datums.push({ MetricName: name, Value: -1, Unit: StandardUnit.Count, Timestamp: ts, Dimensions: [] });
|
|
262
|
+
};
|
|
263
|
+
|
|
180
264
|
for (const record of event.Records ?? []) {
|
|
181
265
|
const commit = parseCommitRecord(record);
|
|
182
266
|
if (!commit) continue;
|
|
183
267
|
|
|
184
|
-
const { tool, isAi } = await
|
|
268
|
+
const { tool, isAi } = await resolveOrigin(
|
|
269
|
+
commit.storedOrigin, commit.storedTool, commit.user, commit.traceId,
|
|
270
|
+
);
|
|
185
271
|
const timestamp = new Date(commit.timestamp);
|
|
186
272
|
// CloudWatch rejects PutMetricData timestamps older than 2 weeks (and one
|
|
187
273
|
// bad member rejects the whole batch, wedging the stream in a retry loop).
|
|
@@ -217,17 +303,46 @@ export async function handler(event: StreamEvent): Promise<void> {
|
|
|
217
303
|
continue;
|
|
218
304
|
}
|
|
219
305
|
|
|
220
|
-
// MODIFY — state transition(s). The receiver writes only when in_main
|
|
221
|
-
// was_reverted actually changed, and a single MODIFY can carry
|
|
222
|
-
|
|
223
|
-
|
|
306
|
+
// MODIFY — state transition(s). The receiver writes only when in_main,
|
|
307
|
+
// was_reverted or ai_origin actually changed, and a single MODIFY can carry
|
|
308
|
+
// more than one.
|
|
309
|
+
|
|
310
|
+
// human → ai-generated. The INSERT already published this commit as human,
|
|
311
|
+
// so the AI counts are published AND the superseded human counts retracted.
|
|
312
|
+
// Without the retraction HumanCommits keeps a phantom that no later event
|
|
313
|
+
// clears, and AI share reads low forever.
|
|
314
|
+
if (commit.originUpgraded) {
|
|
315
|
+
upgraded++;
|
|
316
|
+
aiCommits++;
|
|
317
|
+
retract('HumanCommits', metricTimestamp);
|
|
318
|
+
emit('AICommits', metricTimestamp, tool);
|
|
319
|
+
if (commit.inMain) {
|
|
320
|
+
// in_main was already true at INSERT (CI seeds merged commits), so
|
|
321
|
+
// mergedNow is false and this is the only chance to move the merged
|
|
322
|
+
// count onto the AI series — the one the AI Defect Trend widget reads.
|
|
224
323
|
mergedAi++;
|
|
324
|
+
retract('MergedHumanCommits', metricTimestamp);
|
|
225
325
|
emit('MergedAICommits', metricTimestamp, tool);
|
|
326
|
+
}
|
|
327
|
+
if (commit.wasReverted) {
|
|
328
|
+
revertedAi++;
|
|
329
|
+
emit('RevertedAICommits', metricTimestamp, tool);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
if (commit.mergedNow) {
|
|
334
|
+
if (isAi) {
|
|
335
|
+
// Already counted by the originUpgraded branch above when both fired in
|
|
336
|
+
// the same event; counting twice would double the denominator.
|
|
337
|
+
if (!commit.originUpgraded) {
|
|
338
|
+
mergedAi++;
|
|
339
|
+
emit('MergedAICommits', metricTimestamp, tool);
|
|
340
|
+
}
|
|
226
341
|
} else {
|
|
227
342
|
emit('MergedHumanCommits', metricTimestamp);
|
|
228
343
|
}
|
|
229
344
|
}
|
|
230
|
-
if (commit.revertedNow && isAi) {
|
|
345
|
+
if (commit.revertedNow && isAi && !commit.originUpgraded) {
|
|
231
346
|
revertedAi++;
|
|
232
347
|
emit('RevertedAICommits', metricTimestamp, tool);
|
|
233
348
|
}
|
|
@@ -243,6 +358,7 @@ export async function handler(event: StreamEvent): Promise<void> {
|
|
|
243
358
|
|
|
244
359
|
console.log(
|
|
245
360
|
`[attribution-metrics-publisher] records=${event.Records?.length ?? 0} ` +
|
|
246
|
-
`ai=${aiCommits} human=${humanCommits} merged=${mergedAi} reverted=${revertedAi}
|
|
361
|
+
`ai=${aiCommits} human=${humanCommits} merged=${mergedAi} reverted=${revertedAi} ` +
|
|
362
|
+
`upgraded=${upgraded} datums=${datums.length}`,
|
|
247
363
|
);
|
|
248
364
|
}
|
|
@@ -2,6 +2,7 @@ import { PERSISTED_SECTIONS, validateEventShape } from './event-schema';
|
|
|
2
2
|
import {
|
|
3
3
|
DynamoDBClient,
|
|
4
4
|
PutItemCommand,
|
|
5
|
+
UpdateItemCommand,
|
|
5
6
|
} from '@aws-sdk/client-dynamodb';
|
|
6
7
|
import {
|
|
7
8
|
CloudWatchClient,
|
|
@@ -864,11 +865,25 @@ function mapUnit(unit: string): StandardUnit {
|
|
|
864
865
|
*
|
|
865
866
|
* OR (ai_origin = :human AND :ao = :ai)
|
|
866
867
|
*
|
|
867
|
-
*
|
|
868
|
-
*
|
|
869
|
-
*
|
|
870
|
-
*
|
|
871
|
-
*
|
|
868
|
+
* Two writes, because the two fields have different ownership:
|
|
869
|
+
*
|
|
870
|
+
* ai_origin — either side may write it; the receiver upgrades human→ai and
|
|
871
|
+
* refuses ai→human, so ordering is genuinely irrelevant.
|
|
872
|
+
* in_main — ONLY this function can write it. A PR merge is the only event
|
|
873
|
+
* that knows a commit reached the default branch; the receiver leaves
|
|
874
|
+
* in_main alone on existing items because codeburn cannot know about
|
|
875
|
+
* merges.
|
|
876
|
+
*
|
|
877
|
+
* Write 1 is create-if-absent. Write 2 promotes in_main on an item that
|
|
878
|
+
* already existed, which Write 1 cannot do — its condition is
|
|
879
|
+
* attribute_not_exists(pk), all-or-nothing on the whole item, so a
|
|
880
|
+
* pre-existing commit loses the in_main=true silently.
|
|
881
|
+
*
|
|
882
|
+
* That mattered only for the coding agent. Human codeburn syncs run on a 12h
|
|
883
|
+
* schedule so the merge event effectively always arrives first and Write 1
|
|
884
|
+
* covers it; the agent's emit_commit fires synchronously at commit time, tens
|
|
885
|
+
* of seconds ahead of the merge event, so its commits always pre-existed and
|
|
886
|
+
* reported 0 shipped.
|
|
872
887
|
*
|
|
873
888
|
* The repo format from the CI workflow is bare (owner/name), but codeburn
|
|
874
889
|
* stores with a host prefix (github.com/owner/name). We write under the bare
|
|
@@ -894,6 +909,7 @@ async function seedCommitAttribution(detailType: string, detail: any): Promise<v
|
|
|
894
909
|
const ttl = Math.floor(Date.now() / 1000) + 365 * 86400; // 1 year
|
|
895
910
|
|
|
896
911
|
let seeded = 0;
|
|
912
|
+
let promoted = 0;
|
|
897
913
|
for (let i = 0; i < shas.length; i++) {
|
|
898
914
|
const sha = shas[i];
|
|
899
915
|
const author = authors[i] ?? ''; // parallel array; may be shorter or absent
|
|
@@ -921,10 +937,9 @@ async function seedCommitAttribution(detailType: string, detail: any): Promise<v
|
|
|
921
937
|
gsi_user_sk: { S: `COMMIT#${timestamp}` },
|
|
922
938
|
} : {}),
|
|
923
939
|
},
|
|
924
|
-
//
|
|
925
|
-
// pushed
|
|
926
|
-
//
|
|
927
|
-
// (retry), this is idempotent.
|
|
940
|
+
// Write 1 of 2: create the item only if it does not already exist, so a
|
|
941
|
+
// commit codeburn pushed first keeps its ai_origin=ai-generated verdict
|
|
942
|
+
// (never downgrade ai→human). Idempotent on processor retry.
|
|
928
943
|
ConditionExpression: 'attribute_not_exists(pk)',
|
|
929
944
|
}));
|
|
930
945
|
seeded++;
|
|
@@ -936,9 +951,61 @@ async function seedCommitAttribution(detailType: string, detail: any): Promise<v
|
|
|
936
951
|
throw err;
|
|
937
952
|
}
|
|
938
953
|
}
|
|
954
|
+
|
|
955
|
+
// Write 2 of 2: promote in_main on an item that already existed.
|
|
956
|
+
//
|
|
957
|
+
// in_main has exactly ONE writer: this CI seed. A PR merge is the only
|
|
958
|
+
// event that knows a commit reached the default branch — the receiver
|
|
959
|
+
// deliberately leaves in_main alone on existing items precisely because
|
|
960
|
+
// codeburn cannot know about merges.
|
|
961
|
+
//
|
|
962
|
+
// Write 1 therefore cannot be the only write. Its condition is
|
|
963
|
+
// attribute_not_exists(pk), which is all-or-nothing on the WHOLE item, so
|
|
964
|
+
// when the commit already exists the in_main=true is discarded along with
|
|
965
|
+
// everything else and the commit never counts as shipped.
|
|
966
|
+
//
|
|
967
|
+
// That was invisible for human developers, whose codeburn sync runs on a
|
|
968
|
+
// 12h schedule: the merge event virtually always arrives first, Write 1
|
|
969
|
+
// creates the item, and in_main is correct. The coding agent breaks the
|
|
970
|
+
// assumption — emit_commit fires synchronously at commit time, tens of
|
|
971
|
+
// seconds BEFORE the merge event, so the agent's own commits always lost
|
|
972
|
+
// the race and reported 0 shipped forever.
|
|
973
|
+
//
|
|
974
|
+
// Only ever false→true: CI reports merges, never un-merges, so this is
|
|
975
|
+
// monotonic and cannot fight the receiver. ai_origin/ai_tool are
|
|
976
|
+
// untouched, leaving the frozen attribution verdict authoritative.
|
|
977
|
+
try {
|
|
978
|
+
await dynamoClient.send(new UpdateItemCommand({
|
|
979
|
+
TableName: AI_USAGE_TABLE,
|
|
980
|
+
Key: {
|
|
981
|
+
pk: { S: `REPO#${repo}` },
|
|
982
|
+
sk: { S: `COMMIT#${sha}` },
|
|
983
|
+
},
|
|
984
|
+
UpdateExpression: 'SET in_main = :true, updated_at = :now',
|
|
985
|
+
// Skip the no-op write when in_main is already true, so the DynamoDB
|
|
986
|
+
// stream does not emit a MODIFY the attribution publisher would have
|
|
987
|
+
// to filter out.
|
|
988
|
+
ConditionExpression: 'attribute_exists(pk) AND in_main = :false',
|
|
989
|
+
ExpressionAttributeValues: {
|
|
990
|
+
':true': { BOOL: true },
|
|
991
|
+
':false': { BOOL: false },
|
|
992
|
+
':now': { S: new Date().toISOString() },
|
|
993
|
+
},
|
|
994
|
+
}));
|
|
995
|
+
promoted++;
|
|
996
|
+
} catch (err: any) {
|
|
997
|
+
// Already true, or the item does not exist because Write 1 just created
|
|
998
|
+
// it with in_main=true. Both are the expected steady state.
|
|
999
|
+
if (err.name !== 'ConditionalCheckFailedException') {
|
|
1000
|
+
console.error(`[seedCommitAttribution] Failed to promote in_main for ${sha}:`, err);
|
|
1001
|
+
throw err;
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
939
1004
|
}
|
|
940
1005
|
|
|
941
|
-
if (seeded > 0) {
|
|
942
|
-
console.log(
|
|
1006
|
+
if (seeded > 0 || promoted > 0) {
|
|
1007
|
+
console.log(
|
|
1008
|
+
`[seedCommitAttribution] repo=${repo} seeded=${seeded} promoted_in_main=${promoted} of ${shas.length}`,
|
|
1009
|
+
);
|
|
943
1010
|
}
|
|
944
1011
|
}
|
|
@@ -231,10 +231,33 @@ export function parseOtlpSpans(payload: OtlpPayload): {
|
|
|
231
231
|
spans: ParsedSpan[];
|
|
232
232
|
attributionSpans: ParsedAttributionSpan[];
|
|
233
233
|
rejected: number;
|
|
234
|
+
/**
|
|
235
|
+
* Per-reason rejection counts.
|
|
236
|
+
*
|
|
237
|
+
* `rejected` alone cost an afternoon of code reading to explain a workshop
|
|
238
|
+
* account showing 5 human / 0 AI commits: the receiver knew exactly which
|
|
239
|
+
* branch fired and reported the string 'Spans missing required attributes or
|
|
240
|
+
* failed validation' for all of them. A wire-contract break is now one log
|
|
241
|
+
* line instead of a bisect over published npm tarballs.
|
|
242
|
+
*/
|
|
243
|
+
rejectedReasons: {
|
|
244
|
+
malformedSpan: number;
|
|
245
|
+
noSession: number;
|
|
246
|
+
noSha: number;
|
|
247
|
+
noRepo: number;
|
|
248
|
+
noProvider: number;
|
|
249
|
+
badTokens: number;
|
|
250
|
+
};
|
|
234
251
|
} {
|
|
235
252
|
const spans: ParsedSpan[] = [];
|
|
236
253
|
const attributionSpans: ParsedAttributionSpan[] = [];
|
|
237
254
|
let rejected = 0;
|
|
255
|
+
let rejectedMalformed = 0;
|
|
256
|
+
let rejectedNoSession = 0;
|
|
257
|
+
let rejectedNoSha = 0;
|
|
258
|
+
let rejectedNoRepo = 0;
|
|
259
|
+
let rejectedNoProvider = 0;
|
|
260
|
+
let rejectedBadTokens = 0;
|
|
238
261
|
|
|
239
262
|
for (const rs of payload.resourceSpans ?? []) {
|
|
240
263
|
const resourceAttrs = attrMap(rs.resource?.attributes);
|
|
@@ -249,6 +272,7 @@ export function parseOtlpSpans(payload: OtlpPayload): {
|
|
|
249
272
|
const timestamp = nanoToIso(span.startTimeUnixNano);
|
|
250
273
|
|
|
251
274
|
if (!/^[0-9a-f]{16}$/i.test(spanId) || !timestamp) {
|
|
275
|
+
rejectedMalformed++;
|
|
252
276
|
rejected++;
|
|
253
277
|
continue;
|
|
254
278
|
}
|
|
@@ -256,15 +280,33 @@ export function parseOtlpSpans(payload: OtlpPayload): {
|
|
|
256
280
|
// --- Attribution spans ---
|
|
257
281
|
const attrKind = ATTRIBUTION_SPAN_NAMES[spanName];
|
|
258
282
|
if (attrKind) {
|
|
259
|
-
|
|
260
|
-
|
|
283
|
+
// Session identity moved twice across codeburn releases: `ai.session_id`
|
|
284
|
+
// (<= 0.9.20) -> dropped entirely (0.9.21, 0.9.22) -> `ai.work_unit_id`
|
|
285
|
+
// (0.9.23+). This used to hard-reject when `ai.session_id` was absent,
|
|
286
|
+
// which silently discarded EVERY attribution fact from any codeburn
|
|
287
|
+
// newer than 0.9.20 -- both kinds, because the check ran before the
|
|
288
|
+
// session/commit split. The dashboard then showed 100% human commits
|
|
289
|
+
// with no error surfaced anywhere.
|
|
290
|
+
//
|
|
291
|
+
// Falling back to traceId is sound, not a workaround: codeburn derives
|
|
292
|
+
// the traceId FROM the session id (deriveTraceId(sessionId)), and
|
|
293
|
+
// traceId -- not sessionId -- is the key every join in this file uses
|
|
294
|
+
// (buildUserTraceMap, resolveStoredOrigin). Rejecting on a field the
|
|
295
|
+
// join never reads was strictly worse than accepting the span.
|
|
296
|
+
const sessionId =
|
|
297
|
+
str(attrs.get('ai.session_id')) ||
|
|
298
|
+
str(attrs.get('ai.work_unit_id')) ||
|
|
299
|
+
traceId.toLowerCase();
|
|
300
|
+
if (!sessionId) { rejectedNoSession++; rejected++; continue; }
|
|
261
301
|
|
|
262
302
|
const endTimestamp = nanoToIso(span.endTimeUnixNano) || timestamp;
|
|
263
303
|
const repo = str(attrs.get('git.repo')) || null;
|
|
264
304
|
|
|
265
305
|
if (attrKind === 'commit') {
|
|
266
306
|
const sha = str(attrs.get('git.sha'));
|
|
267
|
-
|
|
307
|
+
// commits without repo can't be joined
|
|
308
|
+
if (!sha) { rejectedNoSha++; rejected++; continue; }
|
|
309
|
+
if (!repo) { rejectedNoRepo++; rejected++; continue; }
|
|
268
310
|
attributionSpans.push({
|
|
269
311
|
kind: 'commit',
|
|
270
312
|
spanId: spanId.toLowerCase(),
|
|
@@ -315,6 +357,7 @@ export function parseOtlpSpans(payload: OtlpPayload): {
|
|
|
315
357
|
// --- Usage spans (existing logic) ---
|
|
316
358
|
const provider = str(attrs.get('ai.provider'));
|
|
317
359
|
if (!provider) {
|
|
360
|
+
rejectedNoProvider++;
|
|
318
361
|
rejected++;
|
|
319
362
|
continue;
|
|
320
363
|
}
|
|
@@ -326,6 +369,7 @@ export function parseOtlpSpans(payload: OtlpPayload): {
|
|
|
326
369
|
inputTokens < 0 || outputTokens < 0 || costUsd < 0 ||
|
|
327
370
|
inputTokens > 100_000_000 || outputTokens > 100_000_000 || costUsd > 10_000
|
|
328
371
|
) {
|
|
372
|
+
rejectedBadTokens++;
|
|
329
373
|
rejected++;
|
|
330
374
|
continue;
|
|
331
375
|
}
|
|
@@ -352,7 +396,19 @@ export function parseOtlpSpans(payload: OtlpPayload): {
|
|
|
352
396
|
}
|
|
353
397
|
}
|
|
354
398
|
|
|
355
|
-
return {
|
|
399
|
+
return {
|
|
400
|
+
spans,
|
|
401
|
+
attributionSpans,
|
|
402
|
+
rejected,
|
|
403
|
+
rejectedReasons: {
|
|
404
|
+
malformedSpan: rejectedMalformed,
|
|
405
|
+
noSession: rejectedNoSession,
|
|
406
|
+
noSha: rejectedNoSha,
|
|
407
|
+
noRepo: rejectedNoRepo,
|
|
408
|
+
noProvider: rejectedNoProvider,
|
|
409
|
+
badTokens: rejectedBadTokens,
|
|
410
|
+
},
|
|
411
|
+
};
|
|
356
412
|
}
|
|
357
413
|
|
|
358
414
|
// ---- Route: discovery doc ----
|
|
@@ -727,7 +783,7 @@ async function handleTraces(event: HttpApiEvent): Promise<HttpApiResponse> {
|
|
|
727
783
|
return jsonResponse(400, { message: 'Body is not valid JSON' });
|
|
728
784
|
}
|
|
729
785
|
|
|
730
|
-
const { spans, attributionSpans, rejected } = parseOtlpSpans(payload);
|
|
786
|
+
const { spans, attributionSpans, rejected, rejectedReasons } = parseOtlpSpans(payload);
|
|
731
787
|
const totalAccepted = spans.length + attributionSpans.length;
|
|
732
788
|
|
|
733
789
|
if (totalAccepted > MAX_BATCH_SIZE) {
|
|
@@ -743,16 +799,30 @@ async function handleTraces(event: HttpApiEvent): Promise<HttpApiResponse> {
|
|
|
743
799
|
// Process attribution spans (new flow)
|
|
744
800
|
const attrWritten = await processAttributionSpans(user, attributionSpans);
|
|
745
801
|
|
|
802
|
+
// Only name the reasons that actually fired — a always-present zero-filled
|
|
803
|
+
// breakdown is noise on the overwhelmingly common clean batch.
|
|
804
|
+
const reasonDetail = Object.entries(rejectedReasons)
|
|
805
|
+
.filter(([, n]) => n > 0)
|
|
806
|
+
.map(([reason, n]) => `${reason}=${n}`)
|
|
807
|
+
.join(' ');
|
|
808
|
+
|
|
746
809
|
console.log(
|
|
747
810
|
`[otel-receiver] user=${user} ` +
|
|
748
811
|
`usage: received=${spans.length} new=${usageWritten} dupes=${spans.length - usageWritten} | ` +
|
|
749
812
|
`attribution: received=${attributionSpans.length} written=${attrWritten} | ` +
|
|
750
|
-
`rejected=${rejected}`,
|
|
813
|
+
`rejected=${rejected}${reasonDetail ? ` (${reasonDetail})` : ''}`,
|
|
751
814
|
);
|
|
752
815
|
|
|
753
816
|
if (rejected > 0) {
|
|
754
817
|
return jsonResponse(200, {
|
|
755
|
-
partialSuccess: {
|
|
818
|
+
partialSuccess: {
|
|
819
|
+
rejectedSpans: rejected,
|
|
820
|
+
// Name the failing validation instead of a generic string: the client
|
|
821
|
+
// prints this, so a contract break is actionable from the CLI output
|
|
822
|
+
// rather than requiring receiver log access.
|
|
823
|
+
errorMessage: `Spans failed validation: ${reasonDetail}`,
|
|
824
|
+
rejectedReasons,
|
|
825
|
+
},
|
|
756
826
|
});
|
|
757
827
|
}
|
|
758
828
|
return jsonResponse(200, {});
|
|
@@ -1257,18 +1327,7 @@ async function handleProductivityQuery(event: HttpApiEvent): Promise<HttpApiResp
|
|
|
1257
1327
|
totals.usage.outputTokens += u.usage.outputTokens;
|
|
1258
1328
|
totals.usage.costUsd += u.usage.costUsd;
|
|
1259
1329
|
totals.usage.calls += u.usage.calls;
|
|
1260
|
-
|
|
1261
|
-
const agg = totals.usage.byTool[tool] ?? { costUsd: 0, calls: 0 };
|
|
1262
|
-
agg.costUsd += t.costUsd;
|
|
1263
|
-
agg.calls += t.calls;
|
|
1264
|
-
totals.usage.byTool[tool] = agg;
|
|
1265
|
-
}
|
|
1266
|
-
for (const [model, m] of Object.entries(u.usage.byModel)) {
|
|
1267
|
-
const agg = totals.usage.byModel[model] ?? { costUsd: 0, calls: 0 };
|
|
1268
|
-
agg.costUsd += m.costUsd;
|
|
1269
|
-
agg.calls += m.calls;
|
|
1270
|
-
totals.usage.byModel[model] = agg;
|
|
1271
|
-
}
|
|
1330
|
+
mergeUsageBreakdowns(totals, u);
|
|
1272
1331
|
totals.commits.total += u.commits.total;
|
|
1273
1332
|
totals.commits.ai += u.commits.ai;
|
|
1274
1333
|
totals.commits.human += u.commits.human;
|
|
@@ -1304,6 +1363,7 @@ async function handleProductivityQuery(event: HttpApiEvent): Promise<HttpApiResp
|
|
|
1304
1363
|
into.usage.outputTokens += u.usage.outputTokens;
|
|
1305
1364
|
into.usage.costUsd += u.usage.costUsd;
|
|
1306
1365
|
into.usage.calls += u.usage.calls;
|
|
1366
|
+
mergeUsageBreakdowns(into, u);
|
|
1307
1367
|
into.commits.total += u.commits.total;
|
|
1308
1368
|
into.commits.ai += u.commits.ai;
|
|
1309
1369
|
into.commits.human += u.commits.human;
|
|
@@ -1525,6 +1585,31 @@ async function handleCommitsDailyQuery(event: HttpApiEvent): Promise<HttpApiResp
|
|
|
1525
1585
|
});
|
|
1526
1586
|
}
|
|
1527
1587
|
|
|
1588
|
+
/**
|
|
1589
|
+
* Merge one user's byTool/byModel spend maps into an accumulator.
|
|
1590
|
+
*
|
|
1591
|
+
* Shared by the fleet-total and the human/agent-split loops. It exists as a
|
|
1592
|
+
* function because it did not: the split loop was written later and summed
|
|
1593
|
+
* costUsd, calls, commits and issues but not these two maps, so `totals.usage.byTool`
|
|
1594
|
+
* arrived at the dashboard empty while every scalar beside it was correct. The
|
|
1595
|
+
* Detail view then rendered "no by tool data" next to a populated cost-per-commit
|
|
1596
|
+
* figure. Two loops summing the same shape is the drift; one function is the fix.
|
|
1597
|
+
*/
|
|
1598
|
+
function mergeUsageBreakdowns(into: UserProductivity, from: UserProductivity): void {
|
|
1599
|
+
for (const [tool, t] of Object.entries(from.usage.byTool)) {
|
|
1600
|
+
const agg = into.usage.byTool[tool] ?? { costUsd: 0, calls: 0 };
|
|
1601
|
+
agg.costUsd = Math.round((agg.costUsd + t.costUsd) * 10000) / 10000;
|
|
1602
|
+
agg.calls += t.calls;
|
|
1603
|
+
into.usage.byTool[tool] = agg;
|
|
1604
|
+
}
|
|
1605
|
+
for (const [model, m] of Object.entries(from.usage.byModel)) {
|
|
1606
|
+
const agg = into.usage.byModel[model] ?? { costUsd: 0, calls: 0 };
|
|
1607
|
+
agg.costUsd = Math.round((agg.costUsd + m.costUsd) * 10000) / 10000;
|
|
1608
|
+
agg.calls += m.calls;
|
|
1609
|
+
into.usage.byModel[model] = agg;
|
|
1610
|
+
}
|
|
1611
|
+
}
|
|
1612
|
+
|
|
1528
1613
|
function accumulateUsage(u: UserProductivity, item: Record<string, { S?: string; N?: string }>): void {
|
|
1529
1614
|
const tool = item.tool?.S ?? 'unknown';
|
|
1530
1615
|
const cost = Number(item.cost_usd?.N ?? 0);
|
|
@@ -9,7 +9,9 @@
|
|
|
9
9
|
"synth": "cdk synth",
|
|
10
10
|
"deploy": "cdk deploy --all",
|
|
11
11
|
"diff": "cdk diff",
|
|
12
|
-
"check:metrics": "tsx scripts/check-metric-coverage.ts"
|
|
12
|
+
"check:metrics": "tsx scripts/check-metric-coverage.ts",
|
|
13
|
+
"check:attribution": "tsx scripts/check-attribution-contract.ts",
|
|
14
|
+
"check:transitions": "tsx scripts/check-commit-transitions.ts"
|
|
13
15
|
},
|
|
14
16
|
"dependencies": {
|
|
15
17
|
"aws-cdk-lib": "^2.170.0",
|
|
@@ -17,9 +19,13 @@
|
|
|
17
19
|
"constructs": "^10.4.2"
|
|
18
20
|
},
|
|
19
21
|
"devDependencies": {
|
|
22
|
+
"@aws-sdk/client-cloudwatch": "^3.1121.0",
|
|
23
|
+
"@aws-sdk/client-dynamodb": "^3.1121.0",
|
|
24
|
+
"@aws-sdk/client-s3": "^3.1121.0",
|
|
20
25
|
"@types/node": "^20.17.0",
|
|
26
|
+
"aws-cdk": "^2.170.0",
|
|
21
27
|
"ts-node": "^10.9.2",
|
|
22
|
-
"
|
|
23
|
-
"
|
|
28
|
+
"tsx": "^4.23.12",
|
|
29
|
+
"typescript": "~5.6.0"
|
|
24
30
|
}
|
|
25
31
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup-github-oidc.d.ts","sourceRoot":"","sources":["../../../../src/commands/bootstrapper/setup-github-oidc.ts"],"names":[],"mappings":";;;;;;;;;;;iBA+CqB;QAAE,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE;;AAP5E,
|
|
1
|
+
{"version":3,"file":"setup-github-oidc.d.ts","sourceRoot":"","sources":["../../../../src/commands/bootstrapper/setup-github-oidc.ts"],"names":[],"mappings":";;;;;;;;;;;iBA+CqB;QAAE,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE;;AAP5E,wBAsTE"}
|
|
@@ -243,10 +243,14 @@ export default {
|
|
|
243
243
|
// The coding agent workflow invokes the harness (InvokeHarness) and runs
|
|
244
244
|
// deterministic shell commands in the same session (InvokeAgentRuntimeCommand)
|
|
245
245
|
// for clone, toolchain install, dependency install, and verification.
|
|
246
|
+
// GetHarness (→ GetAgentRuntime) resolves the model from the harness config
|
|
247
|
+
// as a fallback when the SSM parameter is missing.
|
|
246
248
|
Effect: 'Allow',
|
|
247
249
|
Action: [
|
|
248
250
|
'bedrock-agentcore:InvokeHarness',
|
|
249
251
|
'bedrock-agentcore:InvokeAgentRuntimeCommand',
|
|
252
|
+
'bedrock-agentcore:GetHarness',
|
|
253
|
+
'bedrock-agentcore:GetAgentRuntime',
|
|
250
254
|
],
|
|
251
255
|
Resource: `arn:aws:bedrock-agentcore:${region}:${accountId}:harness/*`,
|
|
252
256
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup-github-oidc.js","sourceRoot":"","sources":["../../../../src/commands/bootstrapper/setup-github-oidc.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"setup-github-oidc.js","sourceRoot":"","sources":["../../../../src/commands/bootstrapper/setup-github-oidc.ts"],"names":[],"mappings":"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"}
|